#include "EPD.h"

#include "main.h"
#include "dma.h"
#include "spi.h"
#include "usart.h"
#include "gpio.h"

#include "string.h"
#include "stdio.h"

#if USE_FORT_FLASH == 1
#include "FLASH.h"
#else
#include "FORT.h"
#endif


//GOIO配置
#define EPD_RES_SET()  	 HAL_GPIO_WritePin(EPD_RES_GPIO_Port,EPD_RES_Pin,GPIO_PIN_SET)
#define EPD_RES_RESET()  HAL_GPIO_WritePin(EPD_RES_GPIO_Port,EPD_RES_Pin,GPIO_PIN_RESET)

#define EPD_DC_SET()  	 HAL_GPIO_WritePin(EPD_DC_GPIO_Port,EPD_DC_Pin,GPIO_PIN_SET)
#define EPD_DC_RESET()   HAL_GPIO_WritePin(EPD_DC_GPIO_Port,EPD_DC_Pin,GPIO_PIN_RESET)

#define EPD_SPI		 			 hspi1


//显存
uint8_t NGRAM[4736];
uint8_t OGRAM[4736];
uint8_t *GRAM[296];


//字符缓冲及起始地址
uint8_t FORT_DATA[500];
uint8_t FORT_TMP[500];
const uint32_t FORT_16_START = 0x000000;
const uint32_t FORT_24_START = 0x200000;
const uint32_t FORT_32_START = 0x680000;

//EPD刷新模式缓存
enum EPD_MODE EPD_REFRESH_MODE      = UNINIT;
enum EPD_MODE EPD_REFRESH_MODE_NOW  = UNINIT;
uint8_t PART_REFRESH_CNT =0;


//EPD局部刷新波形
const uint8_t LUT_PART_VCOM[] =
{	0x00	,0x01	,0x0E	,0x00	,0x00	,0x01,	
	0x00	,0x00	,0x00	,0x00	,0x00	,0x00,	
	0x00	,0x00	,0x00	,0x00	,0x00	,0x00,	
	0x00	,0x00	,0x00	,0x00	,0x00	,0x00,	
	0x00	,0x00	,0x00	,0x00	,0x00	,0x00,	
	0x00	,0x00	,0x00	,0x00	,0x00	,0x00,	
	0x00	,0x00	,0x00	,0x00	,0x00	,0x00	
	,0x00	,0x00,													};

const uint8_t LUT_PART_WW[] =
{	0x00	,0x01	,0x0E	,0x00	,0x00	,0x01,	
	0x00	,0x00	,0x00	,0x00	,0x00	,0x00,	
	0x00	,0x00	,0x00	,0x00	,0x00	,0x00,	
	0x00	,0x00	,0x00	,0x00	,0x00	,0x00,	
	0x00	,0x00	,0x00	,0x00	,0x00	,0x00,	
	0x00	,0x00	,0x00	,0x00	,0x00	,0x00,	
	0x00	,0x00	,0x00	,0x00	,0x00	,0x00,	};

const uint8_t LUT_PART_BW[] =
{	0x20	,0x01	,0x0E	,0x00	,0x00	,0x01,	
	0x00	,0x00	,0x00	,0x00	,0x00	,0x00,	
	0x00	,0x00	,0x00	,0x00	,0x00	,0x00,	
	0x00	,0x00	,0x00	,0x00	,0x00	,0x00,	
	0x00	,0x00	,0x00	,0x00	,0x00	,0x00,	
	0x00	,0x00	,0x00	,0x00	,0x00	,0x00,	
	0x00	,0x00	,0x00	,0x00	,0x00	,0x00,	};

const uint8_t LUT_PART_WB[] =
{	0x10	,0x01	,0x0E	,0x00	,0x00	,0x01,	
	0x00	,0x00	,0x00	,0x00	,0x00	,0x00,	
	0x00	,0x00	,0x00	,0x00	,0x00	,0x00,	
	0x00	,0x00	,0x00	,0x00	,0x00	,0x00,	
	0x00	,0x00	,0x00	,0x00	,0x00	,0x00,	
	0x00	,0x00	,0x00	,0x00	,0x00	,0x00,	
	0x00	,0x00	,0x00	,0x00	,0x00	,0x00,	};

const uint8_t LUT_PART_BB[] =
{	0x00	,0x01	,0x0E	,0x00	,0x00	,0x01,	
	0x00	,0x00	,0x00	,0x00	,0x00	,0x00,	
	0x00	,0x00	,0x00	,0x00	,0x00	,0x00,	
	0x00	,0x00	,0x00	,0x00	,0x00	,0x00,	
	0x00	,0x00	,0x00	,0x00	,0x00	,0x00,	
	0x00	,0x00	,0x00	,0x00	,0x00	,0x00,	
	0x00	,0x00	,0x00	,0x00	,0x00	,0x00,	};

//EPD四阶灰度波形
const unsigned char LUT_GARY_VCOM[] =
{
0x00	,0x0A	,0x00	,0x00	,0x00	,0x01,
0x60	,0x14	,0x14	,0x00	,0x00	,0x01,
0x00	,0x14	,0x00	,0x00	,0x00	,0x01,
0x00	,0x13	,0x0A	,0x01	,0x00	,0x01,
0x00	,0x00	,0x00	,0x00	,0x00	,0x00,
0x00	,0x00	,0x00	,0x00	,0x00	,0x00,
0x00	,0x00	,0x00	,0x00	,0x00	,0x00			};


const uint8_t LUT_GARY_WW[] ={
0x40	,0x0A	,0x00	,0x00	,0x00	,0x01,
0x90	,0x14	,0x14	,0x00	,0x00	,0x01,
0x10	,0x14	,0x0A	,0x00	,0x00	,0x01,
0xA0	,0x13	,0x01	,0x00	,0x00	,0x01,
0x00	,0x00	,0x00	,0x00	,0x00	,0x00,
0x00	,0x00	,0x00	,0x00	,0x00	,0x00,
0x00	,0x00	,0x00	,0x00	,0x00	,0x00,		};

const uint8_t LUT_GARY_BW[] ={
0x40	,0x0A	,0x00	,0x00	,0x00	,0x01,
0x90	,0x14	,0x14	,0x00	,0x00	,0x01,
0x00	,0x14	,0x0A	,0x00	,0x00	,0x01,
0x99	,0x0C	,0x01	,0x03	,0x04	,0x01,
0x00	,0x00	,0x00	,0x00	,0x00	,0x00,
0x00	,0x00	,0x00	,0x00	,0x00	,0x00,
0x00	,0x00	,0x00	,0x00	,0x00	,0x00,		};

const uint8_t LUT_GARY_WB[] ={
0x40	,0x0A	,0x00	,0x00	,0x00	,0x01,
0x90	,0x14	,0x14	,0x00	,0x00	,0x01,
0x00	,0x14	,0x0A	,0x00	,0x00	,0x01,
0x99	,0x0B	,0x04	,0x04	,0x01	,0x01,
0x00	,0x00	,0x00	,0x00	,0x00	,0x00,
0x00	,0x00	,0x00	,0x00	,0x00	,0x00,
0x00	,0x00	,0x00	,0x00	,0x00	,0x00,		};

const uint8_t LUT_GARY_BB[] ={
0x80	,0x0A	,0x00	,0x00	,0x00	,0x01,
0x90	,0x14	,0x14	,0x00	,0x00	,0x01,
0x20	,0x14	,0x0A	,0x00	,0x00	,0x01,
0x50	,0x13	,0x01	,0x00	,0x00	,0x01,
0x00	,0x00	,0x00	,0x00	,0x00	,0x00,
0x00	,0x00	,0x00	,0x00	,0x00	,0x00,
0x00	,0x00	,0x00	,0x00	,0x00	,0x00,		};



//显示溢出错误处理
__weak  void SHOW_CHAR_OVERFLOW_CHAR_EVENT(uint16_t x,uint16_t y,enum FORT_SIZE size,uint32_t unicode,uint8_t bit)
{
	return;
}


//EPD写入数据
void EPD_DAT(uint8_t DAT)
{
	HAL_SPI_Transmit(&EPD_SPI,&DAT,1,0xffff);
}



//EPD写入命令
void EPD_CMD(uint8_t CMD)
{
	EPD_DC_RESET();
	HAL_SPI_Transmit(&EPD_SPI,&CMD,1,0xffff);
	EPD_DC_SET();
}



//EPD繁忙等待
void EPD_BUSY()
{
	while(HAL_GPIO_ReadPin(EPD_BUSY_GPIO_Port,EPD_BUSY_Pin)==GPIO_PIN_RESET)
	{
		HAL_Delay(1);
	}
}


//初始化屏幕缓冲区
void GRAM_INIT()
{
	memset(NGRAM,0x00,sizeof(NGRAM));
	for(uint16_t i=296,j=0;i>0;i--,j+=16)
	{
		GRAM[i-1]=&NGRAM[j];
	}
}

//EPD初始化(使用内置波形)
void EPD_INIT_FULL()
{
	HAL_Delay(20);
	EPD_RES_RESET();
	HAL_Delay(20);
	EPD_RES_SET();
	HAL_Delay(20);
	
	EPD_CMD(0x06);
	EPD_DAT(0x17);
	EPD_DAT(0x17);
	EPD_DAT(0x17);
	
	EPD_CMD(0x04);
	
	EPD_BUSY();
	
	EPD_CMD(0x00);
	EPD_DAT(0x1f);
	EPD_DAT(0x0d);
	
	EPD_CMD(0x61);
	EPD_DAT(0x80);
	EPD_DAT(0x01);
	EPD_DAT(0x28);
	
	EPD_CMD(0x50);
	EPD_DAT(0x87);
}


//EPD写入局部刷新波形
void LUT_PART()
{
	EPD_CMD(0x20);
	HAL_SPI_Transmit(&EPD_SPI,LUT_PART_VCOM,44,0xffff);

	EPD_CMD(0x21);
	HAL_SPI_Transmit(&EPD_SPI,LUT_PART_WW,42,0xffff); 
	
	EPD_CMD(0x22);
	HAL_SPI_Transmit(&EPD_SPI,LUT_PART_BW,42,0xffff); 

	EPD_CMD(0x23);
	HAL_SPI_Transmit(&EPD_SPI,LUT_PART_WB,42,0xffff); 

	EPD_CMD(0x24);
	HAL_SPI_Transmit(&EPD_SPI,LUT_PART_BB,42,0xffff); 
}



//EPD初始化(局部刷新模式)
void EPD_INIT_PART()
{
	HAL_Delay(20);
	EPD_RES_RESET();
	HAL_Delay(20);
	EPD_RES_SET();
	HAL_Delay(20);
	
	EPD_CMD(0x06);
	EPD_DAT(0x17);
	EPD_DAT(0x17);
	EPD_DAT(0x17);
	
	EPD_CMD(0x01);
	EPD_DAT(0x03);
	EPD_DAT(0x00);
	EPD_DAT(0x2b);
	EPD_DAT(0x2b);
	EPD_DAT(0x09);
	
	EPD_CMD(0x04);
	
	EPD_BUSY();
	
	EPD_CMD(0x00);
	EPD_DAT(0x3f);
	
	EPD_CMD(0x30);
	EPD_DAT(0x3c);
	
	EPD_CMD(0x61);
	EPD_DAT(0x80);
	EPD_DAT(0x01);
	EPD_DAT(0x28);
	
	EPD_CMD(0x82);
	EPD_DAT(0x12);
	
	EPD_CMD(0x50);
	EPD_DAT(0x87);
	
	LUT_PART();
}


//EPD写入局部刷新波形
void LUT_GARY()
{
	EPD_CMD(0x20);
	HAL_SPI_Transmit(&EPD_SPI,LUT_GARY_VCOM,44,0xffff);

	EPD_CMD(0x21);
	HAL_SPI_Transmit(&EPD_SPI,LUT_GARY_WW,42,0xffff); 
	
	EPD_CMD(0x22);
	HAL_SPI_Transmit(&EPD_SPI,LUT_GARY_BW,42,0xffff); 

	EPD_CMD(0x23);
	HAL_SPI_Transmit(&EPD_SPI,LUT_GARY_WB,42,0xffff); 

	EPD_CMD(0x24);
	HAL_SPI_Transmit(&EPD_SPI,LUT_GARY_BB,42,0xffff); 
	
	EPD_CMD(0x25);
	HAL_SPI_Transmit(&EPD_SPI,LUT_GARY_WW,42,0xffff); 
}

//EPD初始化(四阶灰度)
void EPD_INIT_GARY()
{
	HAL_Delay(20);
	EPD_RES_RESET();
	HAL_Delay(20);
	EPD_RES_SET();
	HAL_Delay(20);
	
	EPD_CMD(0x06);
	EPD_DAT(0x17);
	EPD_DAT(0x17);
	EPD_DAT(0x17);
	
	EPD_CMD(0x01);
	EPD_DAT(0x03);
	EPD_DAT(0x00);
	EPD_DAT(0x2b);
	EPD_DAT(0x2b);
	EPD_DAT(0x13);
	
	EPD_CMD(0x04);
	
	EPD_BUSY();
	
	EPD_CMD(0x00);
	EPD_DAT(0x3f);
	
	EPD_CMD(0x30);
	EPD_DAT(0x3c);
	
	EPD_CMD(0x61);
	EPD_DAT(0x80);
	EPD_DAT(0x01);
	EPD_DAT(0x28);
	
	EPD_CMD(0x82);
	EPD_DAT(0x12);
	
	EPD_CMD(0x50);
	EPD_DAT(0x87);
	
	LUT_GARY();
	
}
//EPD初始化
void EPD_INIT(enum EPD_MODE mode)
{
	GRAM_INIT();
	
	#if USE_FORT_FLASH == 1
	W25QX_Init();
	#endif 
	
	EPD_REFRESH_MODE = mode;
}


//四阶灰度测试
void GARY_TEST(void)
{
		EPD_INIT_GARY();
	
		unsigned int i,r,t,y;
		
		EPD_CMD(0x10);	  	
		for(y=0;y<1184;y++)	     
		{
			EPD_DAT(0xff);  //white
		}  
		for(t=0;t<1184;t++)	     
		{ 
			EPD_DAT(0xff);  //gray1
		}  
		for(r=0;r<1184;r++)	     
		{
			EPD_DAT(0x00);  //gray2
		}  
		for(i=0;i<1184;i++)	     
		{
			EPD_DAT(0x00);  //black
		}  
		EPD_CMD(0x13);
		for(i=0;i<1184;i++)	     
		{
			EPD_DAT(0xff);  //white
		}  
		for(r=0;r<1184;r++)	     
		{
			EPD_DAT(0x00); //gray1
		}  
		for(t=0;t<1184;t++)	     
		{
			EPD_DAT(0xff);  //gray2
		}  
		for(y=0;y<1184;y++)	     
		{
			EPD_DAT(0x00); //black
		}  
		
		
		EPD_CMD(0x12);
		HAL_Delay(1);
		EPD_BUSY();
	
}



void develop_test()
{

}



//EPD更新屏幕缓冲到屏幕
void EPD_REFRESH()
{
	switch(EPD_REFRESH_MODE)
	{
		case FULL: {if(EPD_REFRESH_MODE_NOW != FULL) {EPD_INIT_FULL(); EPD_REFRESH_MODE_NOW=FULL; } break;};
		case PART: {if(EPD_REFRESH_MODE_NOW != PART) {EPD_INIT_PART(); EPD_REFRESH_MODE_NOW=PART; } break;};
		case MIX:  {
								 //首次刷新采用全局刷新
								 if(EPD_REFRESH_MODE_NOW == UNINIT) {EPD_INIT_FULL(); EPD_REFRESH_MODE_NOW=FULL; break;}
								 //二次刷新采用局部刷新
								 if(EPD_REFRESH_MODE_NOW == FULL) 	{EPD_INIT_PART(); EPD_REFRESH_MODE_NOW=PART; PART_REFRESH_CNT++; break;}
								 //判断当前局部刷新次数选择刷新模式
								 if(EPD_REFRESH_MODE_NOW == PART) 	
									 {
											if(PART_REFRESH_CNT<3) {PART_REFRESH_CNT++; break;}
											else 									 {EPD_INIT_FULL(); EPD_REFRESH_MODE_NOW=FULL; PART_REFRESH_CNT=0; break;}
									 }
							 };
		default: return;
	}
	
	EPD_CMD(0x10);
	HAL_SPI_Transmit(&EPD_SPI,OGRAM,4736,0xffff);

	EPD_CMD(0x13);
	HAL_SPI_Transmit(&EPD_SPI,NGRAM,4736,0xffff);
	
	EPD_CMD(0x12);
	
	memcpy(OGRAM,NGRAM,sizeof(NGRAM));
	
	EPD_BUSY();
}


//EPD清空屏幕
void EPD_CLEAR()
{
	memset(NGRAM,0x00,sizeof(NGRAM));
}

//EPD进入深度睡眠
void EPD_SLEEP()
{
	EPD_REFRESH_MODE_NOW  = UNINIT;
	PART_REFRESH_CNT =0;
	
	EPD_CMD(0x50);
	EPD_DAT(0xf7);
	
	EPD_CMD(0x02);
	
	EPD_BUSY();
	
	EPD_CMD(0x07);
	EPD_DAT(0xA5);
}

//EPD显示图片(高度仅能为8的倍数/8)
void EPD_SHOW_PICTURE(uint16_t x,uint16_t y,uint16_t length,uint16_t height,uint8_t* pic)
{
	uint16_t cnt=0;
	for(uint16_t i=x;i<x+length;i++)
	{
		for(uint16_t j=y;j<y+height;j++)
		{
			GRAM[i][j]=pic[cnt++];
		}
	}
}


#if USE_FORT_FLASH != 1
//EPD显示单个ASCII字符,返回值为显示的实际宽度(走内部FLASH)
uint8_t EPD_SHOW_ASCII(uint16_t x,uint16_t y,enum FORT_SIZE size,uint8_t unicode)
{
	if((x + size/2 -1)>295) {SHOW_CHAR_OVERFLOW_CHAR_EVENT(x,y,size,unicode,1); return 0;}//超出显示范围，防止访问空指针
	if(size == FORT_16) { EPD_SHOW_PICTURE(x,y,size/2,size/8,ASCII_16[unicode-0x20]); return size/2;};
	if(size == FORT_24) { EPD_SHOW_PICTURE(x,y,size/2,size/8,ASCII_24[unicode-0x20]); return size/2;};
	if(size == FORT_32) { EPD_SHOW_PICTURE(x,y,size/2,size/8,ASCII_32[unicode-0x20]); return size/2;};
	return 0;//字号不正确
}
#endif


#if USE_FORT_FLASH == 1
//扫描显示实际宽度
uint8_t FORT_GET_WIDE(enum FORT_SIZE size)
{
	uint8_t St=0,Ed=0;
	//扫描起始
	for(int16_t i=0;i< size*size/8;i++)
		if(FORT_TMP[i]!=0){St= i/(size/8);break;}
	//扫描截止
	for(int16_t i=(size*size/8)-1;i>=0 ;i--)
		if(FORT_TMP[i]!=0){Ed= i/(size/8);break;}
	//判断是否为空字符
	if(St==0 && Ed==0) return 0;
	//将缓存数据写入显示缓冲
	for(uint16_t pot=0,cnt = St*(size/8);cnt<((Ed+1)*(size/8));cnt++,pot++)
		FORT_DATA[pot] = FORT_TMP[cnt];
	//返回字符实际宽度
	return (Ed-St+1);
}
#endif


#if USE_FORT_FLASH == 1
//从FLASH读取字符,返回显示宽度
uint8_t READ_FORT(uint32_t Unicode,enum FORT_SIZE size)
{
	uint32_t Address = 0;
	
	switch(size)
	{
		case FORT_16:  {Address = FORT_16_START + Unicode * (size*size/8);break;}
		case FORT_24:  {Address = FORT_24_START + Unicode * (size*size/8);break;}
		case FORT_32:  {Address = FORT_32_START + Unicode * (size*size/8);break;}
		default:			 return 0;
	}
	
	memset(FORT_TMP,0,sizeof(FORT_TMP));
		
	W25QX_ReadData(Address,FORT_TMP,(size*size/8));
		
	return FORT_GET_WIDE(size);

}
#endif



//字符显示事件处理,返回显示宽度
uint8_t SHOW_CHAR(uint16_t x,uint16_t y,enum FORT_SIZE size,uint32_t unicode,uint8_t bit)
{
	#if USE_FORT_FLASH == 1
	
	uint8_t Wide = READ_FORT(unicode,size);
	
	if(x + Wide -1 >  295) {SHOW_CHAR_OVERFLOW_CHAR_EVENT(x,y,size,unicode,bit);return 0;} //清除超出范围的显示
	
	EPD_SHOW_PICTURE(x,y,Wide,size/8,FORT_DATA);
	
	if(x + Wide -1 == 295) return (Wide);
	else 									 return (Wide+SHOW_CHAR_INTERVAL);
	
	#else
	
	if(bit == 1)
		return EPD_SHOW_ASCII(x,y,size,unicode);
	else 
		return 0;
	
	#endif
}


//EPD显示文字(不支持阿拉伯语(能显示，但是是错误的)!!!!!!!!!!!)
void EPD_SHOW_STRING(uint16_t x,uint16_t y,enum FORT_SIZE size,char* string)
{
	uint32_t Unicode=0;
	uint16_t Cnt=0;
	
	while(string!=NULL && (*string)!=0)
	{
				 if(((*string)&0b10000000)==0) {if(Cnt) {x+=(SHOW_CHAR(x,y,size,Unicode,Cnt));} Cnt=1; Unicode=(*string); string++; continue;} //ASCII 0xxxxxxx
		else if(((*string)&0b01000000)==0) {if(Cnt==0){string++; continue;}	/*如果存在首字节错误的情况跳过延续*/ Cnt++; Unicode<<=6; Unicode |= (*string & 0b00111111); string++; continue;} //unicode延续字节
		else if(((*string)&0b00100000)==0) {if(Cnt) {x+=SHOW_CHAR(x,y,size,Unicode,Cnt);} Cnt=1; Unicode=(*string & 0b00011111); string++; continue;} //unicode双字节起始
		else if(((*string)&0b00010000)==0) {if(Cnt) {x+=SHOW_CHAR(x,y,size,Unicode,Cnt);} Cnt=1; Unicode=(*string & 0b00001111); string++; continue;} //unicode三字节起始
		else if(((*string)&0b00001000)==0) {if(Cnt) {x+=SHOW_CHAR(x,y,size,Unicode,Cnt);} Cnt=1; Unicode=(*string & 0b00000111); string++; continue;} //unicode四字节起始
		else {Unicode=0; Cnt=0; string++; continue;}//格式错误字节跳过
	}
	if(Cnt) x+=SHOW_CHAR(x,y,size,Unicode,Cnt);
	
	return;
}